#include "hash.h"

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define FORECAH(item, iterable) for (item = iterable; item != NULL; item = item->next)
#define FORI(i, s, e) for (int i = s; i < e; ++i)

Node *HashMapGet(HashMap *map, Node node)
{
    Node *pList = map->list[node.key % MAX_SIZE];
    Node *pNode = NULL;
    FORECAH(pNode, pList)
    {
        if (pNode->key == node.key)
            return pNode;
    }
    return NULL;
}

STATUS HashMapPut(HashMap *map, Node node)
{
    Node *pList = map->list[node.key % MAX_SIZE];
    Node *pNode = NULL;
    Node *pPreNode = NULL;

    FORECAH(pNode, pList)
    {
        if (pNode->key == node.key)
        {
            pNode->value = node.value;
            return OK;
        }
        pPreNode = pNode;
    }

    pNode = (Node *)malloc(sizeof(Node));
    pNode->key = node.key;
    pNode->value = node.value;
    pNode->next = NULL;
    ++(map->count);

    if (pList == NULL)
    {
        map->list[node.key % MAX_SIZE] = pNode;
    }
    else
    {
        pPreNode->next = pNode;
    }
    return OK;
}

STATUS HashMapDel(HashMap *map, Node node)
{
    Node *pList = map->list[node.key % MAX_SIZE];
    Node *pNode = NULL;
    Node *pPreNode = NULL;

    FORECAH(pNode, pList)
    {
        if (pNode->key == node.key)
        {
            if (pPreNode == NULL)
            {
                map->list[node.key % MAX_SIZE] = pNode->next;
            }
            else
            {
                pPreNode->next = pNode->next;
            }
            free(pNode);
            --(map->count);
            return OK;
        }
        pPreNode = pNode;
    }
    return OK;
}

HashMap *HashMapEMPTY()
{
    HashMap *map = (HashMap *)malloc(sizeof(HashMap));
    if (map == NULL)
        return NULL;
    memset(map, 0, sizeof(HashMap));
    map->put = HashMapPut;
    map->get = HashMapGet;
    map->del = HashMapDel;
    return map;
}

STATUS HashMapDestroy(HashMap *map)
{
    Node *pNode = NULL;
    Node *pPreNode = NULL;

    FORI(i, 0, MAX_SIZE)
    {
        for (pNode = map->list[i]; pNode != NULL;)
        {
            pPreNode = pNode;
            pNode = pNode->next;
            free(pPreNode);
            --(map->count);
        }
    }
    free(map);
    return OK;
}